package spitfire.ksim.algorithm;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import spitfire.ksim.data.KNodeSnapshot;
import spitfire.ksim.data.KSensorSnapshot;

public class KFuzzyRuleBase {

	private Map<String, List<FuzzyEntry>> typeEntryMap = new HashMap<String, List<FuzzyEntry>>(6);
	private String algorithmSpec;
	private RequestAlgorithm reqAlgo;
	private RuleExtractionAlgorithm extrAlgo = new RuleExtractionImpl();
	
	public void setRequestAlgorithm(String algorithmSpec) {
		this.algorithmSpec = algorithmSpec;
		System.out.println("Using " + algorithmSpec + " RuleBase algorithm");
		reqAlgo = RequestAlgoFactory.getRequestAlgorithm(algorithmSpec);
	}

	public String getRequestAlgorithmName() {
		return algorithmSpec;
	}

	public List<FuzzyEntry> getFuzzyEntryList(String sensorType) {
		return typeEntryMap.get(sensorType);
	}
	
	public boolean containsSensorType(String sensorType) {
		return typeEntryMap.containsKey(sensorType);
	}
	
	public String requestForSD(KNodeSnapshot snapshot) {
		if (reqAlgo == null) {
			throw new NullPointerException("Request algorithm hasn't been set");
		}
		return reqAlgo.requestForSD(this, snapshot);
	}

	public void updateRuleBase(KNodeSnapshot snapshot, String sd, String nodeId) {
		Map<String, KSensorSnapshot> typeSnrSnapShotMap = snapshot.getSensorSnapshotMap();
		for (Entry<String, KSensorSnapshot> entry : typeSnrSnapShotMap.entrySet()) {
			String sensorType = entry.getKey();
			List<Long> timeStampList = entry.getValue().getTimeStampList();
			List<Double> dataList = entry.getValue().getDataList();
			FuzzyRule rule = extrAlgo.extractRule(timeStampList, dataList);
			if (rule != null) {
				updateRuleBase(nodeId, sensorType, sd, rule);
			}
		}
	}
	
	public void updateRuleBase(String nodeId, String sensorType, String sd, FuzzyRule rule) {
		if (rule == null || nodeId == null || sensorType == null || sd == null) {
			throw new NullPointerException();
		}
		List<FuzzyEntry> entryList = null;
		if (typeEntryMap.containsKey(sensorType)) {
			// sensor type exists
			entryList = typeEntryMap.get(sensorType);
		} else {
			// sensor type doesn't exist 
			entryList = new ArrayList<FuzzyEntry>();
			typeEntryMap.put(sensorType, entryList);
		}
		
		for (FuzzyEntry entry : entryList) {
			if (entry.match(nodeId, sensorType)) {
				// Fuzzy entry exists
				entry.setSd(sd);
				entry.setRule(rule);
				return;
			}
		}
		// Fuzzy entry doesn't exist
		entryList.add(new FuzzyEntry(nodeId, sensorType, sd, rule));
	}
	
//	
//	private void updateFuzzyDB(String sensorType, FuzzyEntry fe) {
//		List<FuzzyEntry> entryList = null;
//		if (typeEntryMap.containsKey(sensorType)) {
//			entryList = typeEntryMap.get(sensorType);
//		} else {
//			entryList = new ArrayList<FuzzyEntry>();
//			typeEntryMap.put(sensorType, entryList);
//		}
//		
//		FuzzyEntry found = null;
//		for (FuzzyEntry entry : entryList) {
//			if (fe.SD.equalsIgnoreCase(entry.SD)) {
//				found = entry;
//				break;
//			}
//		}
//		if (found != null) {
//			//System.out.println("Found exsisting SD: "+found.SD);
//			FuzzySubEntry se = (FuzzySubEntry)fe.subEntry.get(0);
//			FuzzySubEntry found1 = null;
//			for (int j=0; j<found.subEntry.len(); j++) {
//				FuzzySubEntry fse = (FuzzySubEntry)found.subEntry.get(j);
//				if (fse.sType.equalsIgnoreCase(se.sType)) {
//					found1 = fse;
//					break;
//				}
//			}
//			if (found1 != null) {
//				found1.rule = se.rule;
//				//System.out.println(found.SD+"has exsisting sensorType: "+se.sType);
//			} else {
//				found.subEntry.enList(se);
//				//System.out.println("Add new sensorType: "+se.sType+" for "+found.SD);
//			}
//		}	else {
//			entryList.add(fe);
//			//System.out.println("Add new SD: "+fe.SD);
//		}
//	}
}
